﻿using System;
using System.IO;
using System.Net;
using System.Data;
using System.Diagnostics;

namespace Toybox.CookieGetterSharp.SQLite
{
  /// <summary>
  /// SQLiteを利用してクッキーを保存するタイプのブラウザからクッキーを取得するクラス
  /// </summary>
  abstract class AbstractSqlCookieGetter : CookieGetter
  {
    #region Constructor
    public AbstractSqlCookieGetter(CookieStatus status)
      : base(status)
    {
    }
    #endregion

    #region Override
    public override Cookie GetCookie(Uri url, string key)
    {
      CookieContainer container = GetCookies(base.CookiePath, MakeQuery(url, key));
      CookieCollection collection = container.GetCookies(Utility.AddSrashLast(url));
      return collection[key];
    }

    public override CookieCollection GetCookieCollection(Uri url)
    {
      CookieContainer container = GetCookies(base.CookiePath, MakeQuery(url));
      return container.GetCookies(Utility.AddSrashLast(url));
    }

    public override CookieContainer GetAllCookies()
    {
      return GetCookies(base.CookiePath, MakeQuery());
    }
    #endregion

    protected virtual CookieContainer GetCookies(string path, string query)
    {
      if (path == null || !File.Exists(path))
      {
        throw new CookieGetterException("クッキーパスが正しく設定されていません。");
      }

      CookieContainer container = new CookieContainer();

      string temp = null;
      try
      {
        temp = Path.GetTempFileName();
        File.Copy(path, temp, true);

        using (SQLiteWrap sql = new SQLiteWrap(temp))
        {
          sql.Open();
          DataTable dt = sql.ExecuteQuery(query);
          foreach (DataRow row in dt.Rows)
          {
            Cookie cookie = DataToCookie(row.ItemArray);
            try
            {
              Utility.AddCookieToContainer(container, cookie);
            }
            catch (Exception ex)
            {
              CookieGetter.Exceptions.Enqueue(ex);
              //Console.WriteLine(string.Format("Invalid Format! domain:{0},key:{1},value:{2}", cookie.Domain, cookie.Name, cookie.Value));
              Trace.WriteLine(string.Format("Invalid Format! domain:{0},key:{1},value:{2}", cookie.Domain, cookie.Name, cookie.Value));
            }
          }
          sql.Close();
        }
      }
      catch (Exception ex)
      {
        throw new CookieGetterException("クッキーを取得中、Sqliteアクセスでエラーが発生しました。", ex);
      }
      finally
      {
        if (temp != null)
        {
          File.Delete(temp);
        }
      }

      return container;
    }

    /// <summary>
    /// SQLから取得したデータをクッキーに変換する
    /// </summary>
    /// <param name="data">指定されたQueryで取得した１行分のデータ</param>
    /// <returns></returns>
    protected abstract Cookie DataToCookie(object[] data);

    /// <summary>
    /// すべてのクッキーを取得するためのクエリーを生成する
    /// </summary>
    /// <returns></returns>
    protected abstract string MakeQuery();

    /// <summary>
    /// 指定されたURLに関連したクッキーを取得するためのクエリーを生成する
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    protected abstract string MakeQuery(Uri url);

    /// <summary>
    /// 指定されたURLの名前がkeyであるクッキーを取得するためのクエリーを生成する
    /// </summary>
    /// <param name="url"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    protected abstract string MakeQuery(Uri url, string key);
  }
}
